using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Net;

namespace Hermes.Framework.FileSystem.Ftp
{
    public class FtpExpress : FtpFileSystemTemplate
    {
        protected ConnectionInfo connectionInfo = null;

        protected string currentDirectory = string.Empty;

        public override void Connect(ConnectionInfo connectionInfo)
        {
            this.connectionInfo = connectionInfo;
        }

        public override void ChangeRemoteDirectory(string directoryName)
        {
            this.currentDirectory = directoryName;
        }

        public override void DoDelete(string fileName)
        {
            FtpWebResponse response = GetWebResponse(
                    fileName, WebRequestMethods.Ftp.DeleteFile, true);
            Console.WriteLine("Delete status: {0}", response.StatusDescription);
            response.Close();
        }

        public override bool IsExisted(string fileName)
        {
            FtpWebResponse response = GetWebResponse(
                    fileName, WebRequestMethods.Ftp.GetFileSize, true);
            response.GetResponseStream();
            response.Close();

            return false;
        }

        public override void DoDeleteDirectory(string directoryName)
        {
            FtpWebResponse response = GetWebResponse(
                    directoryName, WebRequestMethods.Ftp.RemoveDirectory, true);
            response.Close();
        }

        public override void DoCreateDirectory(string directoryName)
        {
            FtpWebResponse response = GetWebResponse(
                    directoryName, WebRequestMethods.Ftp.MakeDirectory, true);
            Stream stream = response.GetResponseStream();
            response.Close();
        }

        public FtpWebResponse GetWebResponse(
            string location, string method, bool binary)
        {
            FtpWebRequest ftp = GetWebRequest(location, method, binary);

            return (FtpWebResponse) ftp.GetResponse();
        }

        public FtpWebRequest GetWebRequest(string location, string method, bool binary)
        {
            FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(GetUri(location));
            ftp.Credentials = new NetworkCredential(
                this.connectionInfo.User, this.connectionInfo.Password);
            ftp.Method = method;
            ftp.UseBinary = binary;
            ftp.KeepAlive = false;
            return ftp;
        }

        public override int GetNumberOfItems(string directoryName)
        {
            List<string> items = GetItems(directoryName);

            return items.Count;
        }

        public List<string> GetItems(string directoryName)
        {
            List<string> items = new List<string>();

            try
            {
                FtpWebResponse response = GetWebResponse(
                    directoryName, WebRequestMethods.Ftp.ListDirectory, false);
                StreamReader reader = new StreamReader(response.GetResponseStream());
                string line = reader.ReadLine();
                while (line != null)
                {
                    items.Add(line);
                    line = reader.ReadLine();
                }

                reader.Close();
                response.Close();
            }
            catch (Exception ex)
            {

            }

            return items;
        }

        public override string GetItemName(string directoryName, int index)
        {
            List<string> items = this.GetItems(directoryName);

            return items[index];
        }

        public Uri GetUri(string fileName)
        {
            return new Uri(string.Format(@"ftp://{0}/{1}/{2}", 
                this.connectionInfo.Url, this.currentDirectory, fileName));
        }

        public override void GetFile(string from, string to)
        {
            try
            {
                FileStream outputStream = new FileStream(to, FileMode.Create);
                FtpWebResponse response = GetWebResponse(
                    from, WebRequestMethods.Ftp.DownloadFile, true);

                Stream ftpStream = response.GetResponseStream();
                long cl = response.ContentLength;
                int bufferSize = 2048;
                int readCount;
                byte[] buffer = new byte[bufferSize];

                readCount = ftpStream.Read(buffer, 0, bufferSize);
                while (readCount > 0)
                {
                    outputStream.Write(buffer, 0, readCount);
                    readCount = ftpStream.Read(buffer, 0, bufferSize);
                }

                ftpStream.Close();
                outputStream.Close();
                response.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public override void PutFile(string from, string to)
        {
            FileInfo fileInf = new FileInfo(from);
            FtpWebRequest reqFTP = GetWebRequest(
                to, WebRequestMethods.Ftp.UploadFile, true);

            // Notify the server about the size of the uploaded file
            reqFTP.ContentLength = fileInf.Length;

            // The buffer size is set to 2kb
            int buffLength = 2048;
            byte[] buff = new byte[buffLength];
            int contentLen;

            // Opens a file stream (System.IO.FileStream) to read the file to be uploaded
            FileStream fs = fileInf.OpenRead();

            try
            {
                // Stream to which the file to be upload is written
                Stream strm = reqFTP.GetRequestStream();

                // Read from the file stream 2kb at a time
                contentLen = fs.Read(buff, 0, buffLength);

                // Till Stream content ends
                while (contentLen != 0)
                {
                    // Write Content from the file stream to the FTP Upload Stream
                    strm.Write(buff, 0, contentLen);
                    contentLen = fs.Read(buff, 0, buffLength);
                }

                // Close the file stream and the Request Stream
                strm.Close();
                fs.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public override void DoRename(string from, string to)
        {
            FtpWebResponse response = GetWebResponse(
                    from, WebRequestMethods.Ftp.Rename, true);
            response.Close();
        }

        public override void DoRenameDirectory(string from, string to)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void Dispose()
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
